My object all sublime I shall achieve in time.
W. S. Gilbert

Is it a world to hide virtues in?
William Shakespeare, Twelfth Night

Your public servants serve you right.
Adlai Stevenson

Private faces in public places Are wiser and nicer Than public faces in private places.
W. H. Auden

Answer 6.1
a) struct.
b) dot (.), arrow (->).
c) private.
d) constructor.
e) private.
f) set.
g) Default memberwise copy (performed by the assignment operator).
h) public, private.
i) get.
j) interface.
k) encapsulated.
l) class, struct.
m) public.

Answer 6.2
a) Error: Destructors are not allowed to return values or take arguments.
Correction: Remove the return type void and the parameter int from the declaration.
b) Error: Members cannot be explicitly initialized in the class definition.
Correction: Remove the explicit initialization from the class definition and initialize the data members in a constructor.
c) Error: Constructors are not allowed to return values.
Correction: Remove the return type int from the declaration.

Answers 6.5
The solution to this exercise can be found on your Cyber Classroom CD. Copy the file cpphtp2/answers/P6_05.zip to your hard drive and unzip the program code.

Answers 6.7
The solution to this exercise can be found on your Cyber Classroom CD. Copy the file cpphtp2/answers/P6_07.zip to your hard drive and unzip the program code.
Answers 6.8
The solution to this exercise can be found on your Cyber Classroom CD. Copy the file cpphtp2/answers/P6_08.zip to your hard drive and unzip the program code.

Answers 6.12
The solution to this exercise can be found on your Cyber Classroom CD. Copy the file cpphtp2/answers/P6_12.zip to your hard drive and unzip the program code.
Answers 6.16
The solution to this exercise can be found on your Cyber Classroom CD. Copy the file cpphtp2/answers/P6_16.zip to your hard drive and unzip the program code.
6 Classes and Data Abstraction
6.1Introduction
6.2Structure Definitions
6.3Accessing Members of Structures
6.4Implementing a User-Defined Type Time With a Struct
6.5Implementing a Time Abstract Data Type with a Class
6.6Class Scope and Accessing Class Members
6.7Separating Interface from Implementation
6.8Controlling Access to Members
6.9Access Functions and Utility Functions
6.10Initializing Class Objects: Constructors
6.11Using Default Arguments with Constructors
6.12 Using Destructors
6.13When Constructors and Destructors are Called
6.14Using Data Members and Member Functions
6.15A Subtle Trap: Returning a Reference to a Private Data Member
6.16Assignment by Default Memberwise Copy
6.17Software Reusability
6.18Thinking About Objects: Programming the Classes for the Elevator Simulator
6.19Elevator Laboratory Assignment 5
6.20Summary
Terminology
Figures
6.1 Introduction
Now we begin our introduction to object orientation in C++. Why have we deferred object-oriented programming in C++ until Chapter 6? The answer is that the objects we will build will be composed in part of structured program pieces, so we needed to establish a basis in structured programming first.
Through our "Thinking About Objects" sections at the ends of Chapters 1 through 5, we have introduced the basic concepts (i.e., "object think") and terminology (i.e., "object speak") of object-oriented programming in C++. In these special sections, we also discussed the
techniques of object-oriented design (OOD): We analyzed a typical problem statement that required a system (an elevator simulator) to be built, determined what classes were needed to implement the systems, determined what attributes objects of these classes needed to have, determined what behaviors objects of these classes needed to exhibit, and specified how the objects needed to interact with one another to accomplish the overall goals of the system.
Let us briefly review some key concepts and terminology of object orientation. OOP encapsulates data (attributes) and functions (behavior) into packages called classes; the data and functions of a class are
intimately tied together. A class is like a blueprint. Out of a blueprint, a builder can build a house. Out of a class, a programmer can create an object. One blueprint can be reused many times to make many houses. One class can be reused many times to make many objects of the same class. Classes have the property of information hiding. This means that although class objects may know how to communicate with one another across well-defined interfaces, classes normally are not allowed to know how other classes are implemented--implementation details are hidden within the classes themselves. Surely it is possible to drive a car effectively without knowing the details of
how engines, transmissions and exhaust systems work internally. We will see why information hiding is so crucial to good software engineering.
In C and other procedural programming languages, programming tends to be action-oriented, whereas ideally in C++ programming is object-oriented. In C, the unit of programming is the function. In C++, the unit of programming is the class from which objects are eventually instantiated (i.e., created).
C programmers concentrate on writing functions. Groups of actions that perform some task are formed into functions, and functions are grouped to form programs. Data is certainly important in C, but the view
is that data exists primarily in support of the actions that functions perform. The verbs in a system specification help the C programmer determine the set of functions that will work together to implement the system.
C++ programmers concentrate on creating their own user-defined types called classes. Classes are also referred to as programmer-defined types. Each class contains data as well as the set of functions that manipulate the data. The data components of a class are called data members. The function components of a class are called member functions (or methods in other object-oriented languages). Just as an instance of a built-in type such as int is called a variable, an
instance of a user-defined type (i.e., a class) is called an object. [In the C++ community, the terms variable and object are often used interchangeably.] The focus of attention in C++ is on classes rather than functions. The nouns in a system specification help the C++ programmer determine the set of classes that will be used to create the objects that will work together to implement the system.
Classes in C++ are a natural evolution of the C notion of struct. Before proceeding with the specifics of developing classes in C++, we discuss structures, and we build a user-defined type based on a structure. The
weaknesses we expose in this approach will help motivate the notion of a class.
Select the true statement(s).
Objects normally are not allowed to know how other objects are implemented.
The focus of attention in C++ is creating functions.
Classes are also referred to as programmer-defined types.
6.2 Structure Definitions
Structures are aggregate data types built using elements of other types. Consider the following structure definition:

struct Time {

int hour; // 0-23

int minute; // 0-59

int second; // 0-59

};

The keyword struct introduces the structure definition. The identifier Time is the structure tag that names the structure definition and is used to declare variables of the structure type. In this example, the new type name
is Time. The names declared in the braces of the structure definition are the structure's members. Members of the same structure must have unique names, but two different structures may contain members of the same name without conflict. Each structure definition must end with a semicolon. The preceding explanation is valid for classes also as we will soon see; structures and classes are quite similar in C++.
The definition of Time contains three members of type int--hour, minute, and second. Structure members can be any type, and one structure can contain members of many different types. A structure cannot, however,
contain an instance of itself. For example, a member of type Time cannot be declared in the structure definition for Time. A pointer to another Time structure, however, can be included. A structure containing a member that is a pointer to the same structure type is referred to as a self-referential structure. Self- referential structures are useful for forming linked data structures such as linked lists, queues, stacks and trees as we will see in Chapter 15.
The preceding structure definition does not reserve any space in memory; rather, the definition creates a new data type that is used to declare variables. Structure
variables are declared like variables of other types. The declaration

Time timeObject, timeArray[ 10 ], *timePtr

&timeRef = timeObject;

declares timeObject to be a variable of type Time, timeArray to be an array with 10 elements of type Time, timePtr to be a pointer to a Time object and timeRef to be a reference to a Time object that is initialized with timeObject.
Select the true statement(s).
Structures are created using the struct keyword.
Variable names declared in the braces ({}) of a structure definition are global variables.
Each structure definition must end with a ;.
A structure that contains a pointer member of the same structure type is called a self-referential structure.
6.3 Accessing Members of Structures
Members of a structure (or of a class) are accessed using the member access operators--the dot operator (.) and the arrow operator (->). The dot operator accesses a structure or class member via the variable name for the object or via a reference to the object. For example, to print member hour of structure timeObject use the statement

cout << timeObject.hour;

To print member hour of the structure referenced by timeRef use the statement

cout << timeRef.hour;

The arrow operator--consisting of a minus sign (-) and a greater than sign (>) with no intervening spaces-- accesses a structure member or class member via a pointer to the object. Assume that the pointer timePtr has been declared to point to a Time object, and that the address of structure timeObject has been assigned to timePtr. To print member hour of structure timeObject with pointer timePtr, use the statements

timePtr = &timeObject;

cout << timePtr->hour;

The expression timePtr->hour is equivalent to (*timePtr).hour which dereferences the pointer and accesses the member hour using the dot operator. The
parentheses are needed here because the dot operator (.) has a higher precedence than the pointer dereferencing operator (*). The arrow operator and dot operator, along with parentheses and brackets ([]), have the second highest operator precedence (after the scope resolution operator introduced in Chapter 3) and associate from left to right.
Select the true statement(s).
Operator -> associates from right to left.
The operators -> and . are used to access structure members.
6.4 Implementing a User-Defined Type Time With a Struct
Figure 6.1 creates the user-defined structure type Time with three integer members: hour, minute, and second. The program defines a single Time structure called dinnerTime and uses the dot operator to initialize the structure members with the values 18 for hour, 30 for minute, and 0 for second. The program then prints the time in military format (also called "universal format") and standard format. Note that the print functions receive references to constant Time structures. This causes Time structures to be passed to
the print functions by reference-- thus eliminating the copying overhead associated with passing structures to functions by value-- and the use of const prevents the Time structure from being modified by the print functions. In Chapter 7, we discuss const objects and const member functions.
There are drawbacks to creating new data types with structures in this manner. Since initialization is not specifically required, it is possible to have uninitialized data and the consequent problems. Even if the data is initialized, it may not be initialized correctly. Invalid values can be assigned to the members of a structure (as we did in Fig. 6.1) because the program has direct
access to the data. In lines 30 and 31, the program was easily able to assign bad values to the hour and minute members of the Time object dinnerTime. If the implementation of the struct is changed (e.g., the time could be represented as the number of seconds since midnight), all programs that use the struct must be changed. This is because the programmer directly manipulates the data type. There is no "interface" to it to ensure that the programmer uses the data type correctly and to ensure that the data remains in a consistent state.
There are other problems associated with C-style structures. In C, structures cannot be printed as a unit;
rather, their members must be printed and formatted one at a time. A function could be written to print the members of a structure in some appropriate format. Chapter 8, "Operator Overloading," illustrates how to overload the << operator to enable objects of a structure type or class type to be printed easily. In C, structures may not be compared in their entirety; they must be compared member by member. Chapter 8 also illustrates how to overload equality operators and relational operators to compare objects of (C++) structure and class types.
The following section reimplements our Time structure as a C++ class and demonstrates some of the advantages
to creating so-called abstract data types as classes. We will see that classes and structures can be used almost identically in C++. The difference between the two is in the default accessibility associated with the members of each. This will be explained shortly.
Select the true statement(s).
A structure can be printed as a unit.
A structure's data is directly accessible to a program.
6.5 Implementing a Time Abstract Data Type with a Class
Classes enable the programmer to model objects that have attributes (represented as data members) and behaviors or operations (represented as member functions). Types containing data members and member functions are defined in C++ using the keyword class.
Member functions are sometimes called methods in other object-oriented programming languages, and are invoked in response to messages sent to an object. A message corresponds to a member-function call sent
from one object to another or sent from a function to an object.
Once a class has been defined, the class name can be used to declare objects of that class. Figure 6.2 contains a simple definition for class Time.
Our Time class definition begins with the keyword class. The body of the class definition is delineated with left and right braces ({ and }). The class definition terminates with a semicolon. Our Time class definition and our Time structure definition each contain the three integer members hour, minute, and second.
The remaining parts of the class definition are new. The public: and private: labels are called member access
specifiers. Any data member or member function declared after member access specifier public (and before the next member access specifier) is accessible wherever the program has access to an object of class Time. Any data member or member function declared after member access specifier private (and up to the next member access specifier) is accessible only to member functions of the class. Member access specifiers are always followed by a colon (:) and can appear multiple times and in any order in a class definition. For the remainder of the text, we will refer to the member access specifiers as public and private (without the colon). In Chapter 9 we introduce a third
member access specifier, protected, as we study inheritance and the part it plays in object-oriented programming.
The class definition contains prototypes for the following four member functions after the public member access specifier--Time, setTime, printMilitary, and printStandard. These are the public member functions, or public services, or public behaviors or interface of the class. These functions will be used by clients (i.e., portions of a program that are users) of the class to manipulate the data of the class.
Notice the member function with the same name as the class; it is called a constructor function of that class. A
constructor is a special member function that initializes the data members of a class object. A class's constructor function is called automatically when an object of that class is created. We will see that it is common to have several constructors for a class; this is accomplished through function overloading. Note that no return type is specified for the constructor.
The three integer members appear after the private member access specifier. This indicates that these data members of the class are only accessible to member functions--and, as we will see in the next chapter, "friends"--of the class. Thus, the data members can only be accessed by the four functions whose
prototypes appear in the class definition (or by friends of the class). Data members are normally listed in the private portion of a class and member functions are normally listed in the public portion. It is possible to have private member functions and public data as we will see later; the latter is uncommon and is considered a poor programming practice.
Once the class has been defined, it can be used as a type in declarations as follows:

Time sunset,

// object of type Time

arrayOfTimes[ 5 ],

// array of Time objects

*pointerToTime,


          // pointer to a Time object

&dinnerTime = sunset;

// reference to a Time object

The class name becomes a new type specifier. There may be many objects of a class, just as there may be many variables of a type such as int. The programmer can create new class types as needed. This is one reason why C++ is said to be an extensible language.
Figure 6.3 uses the Time class. The program instantiates a single object of class Time called t. When the object is instantiated, the Time constructor is called automatically and explicitly initializes each private data member to 0. The time is then printed in military
and standard formats to confirm that the members have been initialized properly. The time is then set using the setTime member function and is printed again in both formats. Then setTime attempts to set the data members to invalid values, and the time is again printed in both formats.
Again, note that the data members hour, minute, and second are preceded by the private member access specifier. A class's private data members are normally not accessible outside the class. (Again, we will see in Chapter 7 that friends of a class may access the class's private members.) The philosophy here is that the actual data representation used within the class is of no
concern to the class's clients. For example, it would be perfectly reasonable for the class to represent the time internally as the number of seconds since midnight. Clients could use the same public member functions and get the same results without being aware of this. In this sense, the implementation of a class is said to be hidden from its clients. Such information hiding promotes program modifiability and simplifies the client's perception of a class.
In this program, the Time constructor simply initializes the data members to 0 (i.e., the military time equivalent of 12 AM). This ensures that the object is in a consistent state when it is created. Invalid values cannot
be stored in the data members of a Time object because the constructor is automatically called when the Time object is created and all subsequent attempts by a client to modify the data members are scrutinized by function setTime.
Note that the data members of a class cannot be initialized where they are declared in the class body. These data members should be initialized by the class's constructor, or they can be assigned values by "set" functions.
A function with the same name as the class but preceded with a tilde character (~) is called the destructor of that class (this example does not explicitly
include a destructor so the system "plugs one in" for you). The destructor does "termination housekeeping" on each class object before the memory for the object is reclaimed by the system. Destructors cannot take arguments and hence cannot be overloaded. We will discuss constructors and destructors in more detail later in this chapter and in Chapter 7.
Note that the functions the class provides to the outside world are preceded by the public label. The public functions implement the behaviors or services the class provides to its clients--commonly referred to as the class's interface or public interface.
The class definition contains declarations of the class's data members and the class's member functions. The member function declarations are the function prototypes we discussed in earlier chapters. Member functions can be defined inside a class, but it is a good programming practice to define the functions outside the class definition.
Note the use of the binary scope resolution operator(::) in each member function definition following the class definition in Fig. 6.3. Once a class is defined and its member functions are declared, the member functions must be defined. Each member function of the class can be defined directly in the class body (rather than
including the function prototype of the class), or the member function can be defined after the class body. When a member function is defined after its corresponding class definition, the function name is preceded by the class name and the binary scope resolution operator (::). Because different classes can have the same member names, the scope resolution operator "ties" the member name to the class name to uniquely identify the member functions of a particular class.
Even though a member function declared in a class definition may be defined outside that class definition, that member function is still within that class's scope,
i.e., its name is known only to other members of the class unless referred to via an object of the class, a reference to an object of the class, or a pointer to an object of the class. We will say more about class scope shortly.
If a member function is defined in a class definition, the member function is automatically inlined. Member functions defined outside a class definition may be made inline by explicitly using the keyword inline. Remember that the compiler reserves the right not to inline any function.
It is interesting that the printMilitary and printStandard member functions take no arguments.
This is because member functions implicitly know that they are to print the data members of the particular Time object for which they are invoked. This makes member function calls more concise than conventional function calls in procedural programming.
Classes simplify programming because the client (or user of the class object) need only be concerned with the operations encapsulated or embedded in the object. Such operations are usually designed to be client- oriented rather than implementation-oriented. Clients need not be concerned with a class's implementation (although the client, of course, wants a correct and efficient implementation). Interfaces do change, but
less frequently than implementations. When an implementation changes, implementation-dependent code must change accordingly. By hiding the implementation we eliminate the possibility of other program parts becoming dependent on the details of the class implementation.
Often, classes do not have to be created "from scratch." Rather, they may be derived from other classes that provide attributes and behaviors the new classes can use. Or classes can include objects of other classes as members. Such software reuse can greatly enhance programmer productivity. Deriving new classes from existing classes is called inheritance and is discussed in
detail in Chapter 9. Including class objects as members of other classes is called composition and is discussed in Chapter 7.
People new to object-oriented programming often express concern at the fact that objects must be quite large because they contain data and functions. Logically, this is true--the programmer may think of objects as containing data and functions. Physically, however, this is not true.
Select the true statement(s).
A member function defined outside of the class where it is declared does not have class scope.
Composition is when a class definition contains an object of another class.
A member function's body cannot be defined in the class in which it is declared.
A member function with the same name as the class and preceded with a ~ is called the constructor function.
6.6 Class Scope and Accessing Class Members
A class's data members (variables declared in the class definition) and member functions (functions declared in the class definition) belong to that class's scope. Nonmember functions are defined at file scope.
Within a class's scope, class members are immediately accessible by all of that class's member functions and can be referenced by name. Outside a class's scope, class members are referenced through one of the handles on an object--an object name, a reference to an object, or a pointer to an object. [We will see in Chapter
7 that an implicit handle is inserted by the compiler on every reference to a data member or member function in an object.]
Member functions of a class can be overloaded, but only by other member functions of the class. To overload a member function, simply provide in the class definition a prototype for each version of the overloaded function, and provide a separate function definition for each version of the function.
Member functions have function scope in a class-- variables defined in a member function are known only to that function. If a member function defines a variable with the same name as a variable with class scope, the
class-scope variable is hidden by the function-scope variable in the function scope. Such a hidden variable can be accessed by preceding the operator with the class name followed by the scope resolution operator (::). Hidden global variables can be accessed with the unary scope resolution operator (see Chapter 3).
The operators used to access class members are identical to the operators used to access structure members. The dot member selection operator (.) is combined with an object's name or with a reference to an object to access the object's members. The arrow member selection operator (->) is combined with a pointer to an object to access that object's members.
The program of Fig. 6.4 uses a simple class called Count with public data member x of type int, and public member function print to illustrate accessing the members of a class with the member selection operators. The program instantiates three variables related to type Count--counter, counterRef (a reference to a Count object), and counterPtr (a pointer to a Count object). Variable counterRef is defined to reference counter, and variable counterPtr is defined to point to counter. It is important to note that data member x has been made public here simply to demonstrate how public members are accessed off handles (i.e., a name, a reference or a pointer). As we
have stated, data is typically made private as we will do in most subsequent examples. In Chapter 9, "Inheritance," we will sometimes make data protected.
Select the true statement(s).
Nonmember functions are defined at file scope.
Member functions cannot be overloaded.
Operators . and -> are used to access class members.
6.7 Separating Interface from Implementation
One of the fundamental principles of good software engineering is to separate interface from implementation. This makes it easier to modify programs. As far as clients of a class are concerned, changes in the class's implementation do not affect the client as long as the class's interface originally provided to the client is unchanged (the class's functionality could be expanded beyond the original interface).
Actually, things are not quite this rosy. Header files do contain some portion of the implementation and hints
about other portions of the implementation. Inline member functions, for example, need to be in a header file, so that when the compiler compiles a client, the client can include the inline function definition in place. Private members are listed in the class definition in the header file, so these members are visible to clients even though the clients may not access the private members. In Chapter 7, we show how to use a so-called proxy class to hide even the private data of a class from clients of the class.
Figure 6.5 splits the program of Fig. 6.3 into multiple files. When building a C++ program, each class definition is normally placed in a header file, and that
class's member function definitions are placed in source-code files of the same base name. The header files are included (via #include) in each file in which the class is used, and the source-code file is compiled and linked with the file containing the main program. See your compiler's documentation to determine how to compile and link programs consisting of multiple source files.
Figure 6.5 consists of the header file time1.h in which class Time is declared, the file time1.cpp in which the member functions of class Time are defined, and the file fig06_05.cpp in which function main is defined.
The output for this program is identical to the output of Fig. 6.3.
Note that the class declaration is enclosed in the following preprocessor code:

// prevent multiple inclusions of header file

#ifndef TIME1_H

#define TIME1_H

...

#endif

When we build larger programs, other definitions and declarations will also be placed in header files. The preceding preprocessor directives prevent the code between #ifndef and #endif from being included if the name TIME1_H has been defined. If the header has not
been included previously in a file, the name TIME1_H is defined by the #define directive and the header file statements are included. If the header has been included previously, TIME1_H is defined already and the header file is not included again. Attempts to include a header file multiple times (inadvertently) typically occur in large programs with many header files that may themselves include other header files. Note: The convention we use for the symbolic constant name in the preprocessor directives is simply the header file name with the underscore character replacing the period.
Select the true statement(s).
Header files provide the complete definition of a class's implementation details.
Each class definition is normally placed in a header file.
Header files written by a programmer do not require the use of the preprocessor directive #include.
6.8 Controlling Access to Members
The member access specifiers public and private (and protected as we will see in Chapter 9, "Inheritance") are used to control access to a class's data members and member functions. The default access mode for classes is private so all members after the class header and before the first label are private. After each label, the mode that was invoked by that label applies until the next label or until the terminating right brace (}) of the class definition. The labels public, private, and protected may be repeated, but such usage is rare and can be confusing.
A class's private members can be accessed only by member functions (and friends, as we will see in Chapter 7) of that class. The public members of a class may be accessed by any function in the program.
The primary purpose of public members is to present to the class's clients a view of the services (behaviors) the class provides. This set of services forms the public interface of the class. Clients of the class need not be concerned with how the class accomplishes its tasks. The private members of a class as well as the definitions of its public member functions are not accessible to the clients of a class. These components form the implementation of the class.
F igure 6.6 demonstrates that private class members are only accessible through the public class interface using public member functions. When this program is compiled, the compiler generates two errors stating that the private member specified in each statement is not accessible. Figure 6.6 includes time1.h and is compiled with time1.cpp from Fig. 6.5.
A client of a class may be a member function of another class or it may be a global function (i.e., a C-like "loose" function in the file that is not a member function of any class).
The default access for members of a class is private. Access to members of a class may be explicitly set to
public, protected (as we will see in Chapter 9), or private. The default access for struct members is public. Access to members of a struct also may be explicitly set to public, protected, or private.
Just because class data is private does not necessarily mean that clients cannot effect changes to that data. The data can be changed by member functions or friends of that class. As we will see, these functions should be designed to ensure the integrity of the data.
Access to a class's private data should be carefully controlled by the use of member functions, called access functions (also called accessor methods). For example, to allow clients to read the value of private
data, the class can provide a get function. To enable clients to modify private data, the class can provide a set function. Such modification would seem to violate the notion of private data. But a set member function can provide data validation capabilities (such as range checking) to ensure that the value is set properly. A set function can also translate between the form of the data used in the interface and the form used in the implementation. A get function need not expose the data in "raw" format; rather the get function can edit the data and limit the view of the data the client will see.
Select the true statement(s).
The default access mode for members of a class is private.
The labels public, private, and protected can be repeated in a class definition.
Member functions designated public can only be accessed from outside the class.
Access to members of a struct can be designated public, protected, or private.
6.9 Access Functions and Utility Functions
Not all member functions need be made public to serve as part of the interface of a class. Some member functions remain private and serve as utility functions to the other functions of the class.
Access functions can read or display data. Another common use for access functions is to test the truth or falsity of conditions--such functions are often called predicate functions. An example of a predicate function would be an isEmpty function for any container class--a class capable of holding many objects--such as a linked list, a stack or a queue. A program would
test isEmpty before attempting to read another item from the container object. An isFull predicate function might test a container class object to determine if it has no additional room. A set of useful predicate functions for our Time class might be isAM and isPM.
Figure 6.7 demonstrates the notion of a utility function (also called a helper function). A utility function is not part of a class's interface; rather, it is a private member function that supports the operation of the class's public member functions. Utility functions are not intended to be used by clients of a class.
Class SalesPerson has an array of 12 monthly sales figures initialized by the constructor to zero and set to
user-supplied values by function setSales. Public member function printAnnualSales prints the total sales for the last 12 months. Utility function totalAnnualSales totals the 12 monthly sales figures for the benefit of printAnnualSales. Member function printAnnualSales edits the sales figures into dollar amount format.
Note that main includes only a simple sequence of member function calls--there are no control structures.
Select the true statement(s).
private member functions are often referred to as utility functions.
Functions that return boolean values are often referred to as predicate functions.
Utility functions are designed to called by clients of the class.
6.10 Initializing Class Objects: Constructors
When a class object is created, its members can be initialized by that class's constructor function. A constructor is a class member function with the same name as the class. The programmer provides the constructor which is then invoked automatically each time an object of that class is created (instantiated). Constructors may be overloaded to provide a variety of means for initializing objects of a class. Data members must either be initialized in a constructor of the class, or their values may be set later after the object is created.
When an object of a class is declared, initializers can be provided in parentheses to the right of the object name and before the semicolon. These initializers are passed as arguments to the class's constructor. We will soon see several examples of these constructor calls. [Note: Although programmers do not explicitly call constructors, programmers can still provide data that gets passed to constructors as arguments.]
Select the true statement(s).
Like any other function, constructors can return a value.
Constructors cannot be overloaded.
A constructor is a member function with the same name as the class.
6.11 Using Default Arguments with Constructors
The constructor from time1.cpp ( Fig. 6.5) initialized hour, minute, and second to 0 (i.e., 12 midnight in military time). Constructors can contain default arguments. Figure 6.8 redefines the Time constructor function to include default arguments of zero for each variable. By providing default arguments to the constructor, even if no values are provided in a constructor call, the object is still guaranteed to be initialized to a consistent state due to the default arguments. A programmer-supplied constructor that
defaults all its arguments (or explicitly requires no arguments) is also a default constructor, i.e., a constructor that can be invoked with no arguments. There can be only one default constructor per class.
In this program, the constructor calls member function setTime with the values passed to the constructor (or the default values) to ensure that the value supplied for hour is in the range 0 to 23, and that the values for minute and second are each in the range 0 to 59. If a value is out of range, it is set to zero by setTime (this is an example of ensuring that a data member remains in a consistent state).
Note that the Time constructor could be written to include the same statements as member function setTime. This may be slightly more efficient because the extra call to setTime is eliminated. However, coding the Time constructor and member function setTime identically makes maintenance of this program more difficult. If the implementation of member function setTime changes, the implementation of the Time constructor should change accordingly. Having the Time constructor call setTime directly, requires any changes to the implementation of setTime to be made only once. This reduces the likelihood of a programming error when altering the implementation.
Also, the performance of the Time constructor can be enhanced by explicitly declaring the constructor inline or by defining the constructor in the class definition (which implicitly inlines the function definition).
The program of Fig. 6.8 initializes five Time objects-- one with all three arguments defaulted in the constructor call, one with one argument specified, one with two arguments specified, one with three arguments specified, and one with three invalid arguments specified. The contents of each object's data members after instantiation and initialization are displayed.
If no constructor is defined for a class, the compiler creates a default constructor. Such a constructor does
not perform any initialization, so when the object is created, it is not guaranteed to be in a consistent state.
Select the true statement(s).
A constructor can be inlined.
There can only be one default constructor per class.
Constructors can contain provide default arguments in the parameter list.
6.12 Using Destructors
A destructor is a special member function of a class. The name of the destructor for a class is the tilde (~) character followed by the class name. This naming convention has intuitive appeal, because as we will see in a later chapter the tilde operator is the bitwise complement operator, and, in a sense, the destructor is the complement of the constructor.
A class's destructor is called when an object is destroyed--e.g., when program execution leaves the scope in which an object of that class was instantiated. The destructor itself does not actually destroy the
object--it performs termination housekeeping before the system reclaims the object's memory so that memory may be reused to hold new objects.
A destructor receives no parameters and returns no value. A class may have only one destructor-- destructor overloading is not allowed.
Notice that destructors have not been provided for the classes presented so far. We will soon see several examples of classes with useful destructors. In Chapter 8, we will see that destructors are appropriate for classes whose objects contain dynamically allocated memory (for arrays and strings, for example). In
Chapter 7, we discuss how to dynamically allocate and deallocate storage.
Select the true statement(s).
A destructor is called when an object is removed from memory.
Like a constructor, a destructor can take arguments.
A destructor may return a value.
6.13 When Constructors and Destructors are Called
Constructors and destructors are called automatically. The order in which these function calls are made depends on the order in which execution enters and leaves the scope in which objects are instantiated. Generally, destructor calls are made in the reverse order of the constructor calls. However, as we will see in Fig. 6.9, the storage class of objects can alter the order in which the destructors are called.
Constructors are called for objects defined in global scope before any other function (including main) in
that file begins execution (although the order of execution of global object constructors between files is not guaranteed). The corresponding destructors are called when main terminates or the exit function (see Chapter 18, "Other Topics") is called.
Constructors are called for automatic local objects when execution reaches the point where the objects are defined. The corresponding destructors are called when the objects leave scope (i.e., the block in which they are defined is exited). Constructors and destructors for automatic objects are called each time the objects enter and leave scope.
Constructors are called for static local objects only once when execution first reaches the point where the objects are defined. Corresponding destructors are called when main terminates or the exit function is called.
The program of Fig. 6.9 demonstrates the order in which constructors and destructors are called for objects of type CreateAndDestroy in several scopes. The program defines first in global scope. Its constructor is called as the program begins execution and its destructor is called at program termination after all other objects are destroyed.
Function main declares three objects. Objects second and fourth are local automatic objects, and object third is a static local object. The constructors for each of these objects are called when execution reaches the point where each object is declared. The destructors for objects fourth and second are called in that order when the end of main is reached. Because object third is static, it exists until program termination. The destructor for object third is called before the destructor for first, but after all other objects are destroyed.
Function create declares three objects--fifth and seventh are local automatic objects, and sixth is a
static local object. The destructors for objects seventh and fifth are called in that order when the end of create is reached. Because sixth is static, it exists until program termination. The destructor for sixth is called before the destructors for third and first, but after all other objects are destroyed.
Select the true statement(s).
Constructors and destructors are called automatically.
In general, destructor calls are made in the reverse order of constructor calls.
The programmer must always provide a constructor and destructor for a class.
6.14 Using Data Members and Member Functions
A class's private data members can be manipulated only by member functions (and friends) of the class. A typical manipulation might be the adjustment of a customer's bank balance (e.g., a private data member of a class BankAccount) by a member function computeInterest.
Classes often provide public member functions to allow clients of the class to set (i.e., write) or get (i.e., read) the values of private data members. These functions need not be called set and get specifically, but
they often are. More specifically, a member function that sets data member interestRate would typically be named setInterestRate, and a member function that gets the interestRate would typically be called getInterestRate. Get functions are also commonly called "query" functions.
It may seem that providing both set and get capabilities is essentially the same as making the data members public. This is yet another subtlety of C++ that makes the language so desirable for software engineering. If a data member is public, then the data member may be read or written at will by any function in the program. If a data member is private, a public get function
would certainly seem to allow other functions to read the data at will but the get function could control the formatting and display of the data. A public set function could--and most likely would--carefully scrutinize any attempt to modify the value of the data member. This would ensure that the new value is appropriate for that data item. For example, an attempt to set the day of the month to 37 could be rejected, an attempt to set a person's weight to a negative value could be rejected, an attempt to set a numeric quantity to an alphabetic value could be rejected, an attempt to set a grade on an exam to 185 (when the proper range is zero to 100) could be rejected, etc.
The client of a class should be notified when an attempt is made to assign an invalid value to a data member. A class's set functions are often written to return values indicating that an attempt was made to assign invalid data to an object of the class. This enables clients of the class to test the return values of set functions to determine if the object they are manipulating is a valid object and to take appropriate action if the object is not valid.
Figure 6.10 extends our Time class to include get and set functions for the hour, minute, and second private data members. The set functions strictly control the setting of the data members. Attempts to set any data
member to an incorrect value cause the data member to be set to zero (thus leaving the data member in a consistent state). Each get function simply returns the appropriate data member's value. The program first uses the set functions to set the private data members of Time object t to valid values, then uses the get functions to retrieve the values for output. Next the set functions attempt to set the hour and second members to invalid values and the minute member to a valid value, and then the get functions retrieve the values for output. The output confirms that invalid values cause the data members to be set to zero. Finally, the program sets the time to 11:58:00 and increments the minute
value by 3 with a call to function incrementMinutes. Function incrementMinutes is a nonmember function that uses the get and set member functions to increment the minute member properly. Although this works, it incurs the performance burden of issuing multiple function calls. In the next chapter, we discuss the notion of friend functions as a means of eliminating this performance burden.
Using set functions is certainly important from a software engineering standpoint because they can perform validity checking. Both set and get functions have another important software engineering advantage.
Select the true statement(s).
Get and set functions allow private members to be indirectly accessed.
Set functions are sometimes called query functions.
A set function should perform validity checking.
6.15 A Subtle Trap: Returning a Reference to a Private Data Member
A reference to an object is an alias for the name of the object and hence may be used on the left side of an assignment statement. In this context, the reference makes a perfectly acceptable lvalue that can receive a value. One way to use this capability (unfortunately!) is to have a public member function of a class return a non-const reference to a private data member of that class.
Figure 6.11 uses a simplified Time class to demonstrate returning a reference to a private data member. Such a
return actually makes a call to function badSetHour an alias for the private data member hour! The function call can be used in any way that the private data member can be used, including as an lvalue in an assignment statement!
The program begins by declaring Time object t and reference hourRef that is assigned the reference returned by the call t.badSetHour(20). The program displays the value of the alias hourRef. Next, the alias is used to set the value of hour to 30 (an invalid value) and the value is displayed again. Finally, the function call itself is used as an lvalue and assigned the value 74 (another invalid value), and the value is displayed.
6.16 Assignment by Default Memberwise Copy
The assignment operator (=) can be used to assign an object to another object of the same type. Such assignment is by default performed by memberwise copy--each member of one object is copied individually to the same member in another object (see Fig. 6.12). (Note: Memberwise copy can cause serious problems when used with a class whose data members contain dynamically allocated storage; in Chapter 8, "Operator Overloading," we will discuss these problems and show how to deal with them.)
Objects may be passed as function arguments and may be returned from functions. Such passing and returning is performed call-by-value by default--a copy of the object is passed or returned (we present several examples in Chapter 8, "Operator Overloading").
Select the true statement(s).
Objects are passed by value by default.
Assigning an object to an object of the same type results in default memberwise copy.
6.17 Software Reusability
People who write object-oriented programs concentrate on implementing useful classes. There is a tremendous opportunity to capture and catalog classes so that they can be accessed by large segments of the programming community. Many class libraries exist and others are being developed worldwide. There are efforts to make these libraries broadly accessible. Software is increasingly being constructed from existing, well- defined, carefully tested, well-documented, portable, widely available components. This kind of software reusability speeds the development of powerful, high-
quality software. Rapid applications development (RAD) through the mechanisms of reusable componentry has become an important field.
Significant problems must be solved, however, before the full potential of software reusability can be realized. We need cataloging schemes, licensing schemes, protection mechanisms to ensure that master copies of classes are not corrupted, description schemes so that designers of new systems can determine if existing objects meet their needs, browsing mechanisms to determine what classes are available and how closely they meet software developer requirements, and the like. Many interesting research and development
problems need to be solved. There is great motivation to solve these problems because the potential value of their solutions is enormous.
6.18 Thinking About Objects: Programming the Classes for the Elevator Simulator
In the "Thinking About Objects" sections of Chapters 1 through 5 we introduced the fundamentals of object orientation and walked you through an object-oriented design for an elevator simulator. In the body of Chapter 6, we introduced the details of programming and using C++ classes. At this point, you are ready (and probably eager!) to begin programming your elevator simulator.
6.19 Elevator Laboratory Assignment 5
1. For each of the classes you identified in the "Thinking About Objects" sections of Chapters 2 through 5, write an appropriate C++ class definition. For each class, include both a header file and a member function definition source file.
2. Write a driver program that tests each of these classes, and that attempts to run the complete elevator simulation. CAUTION: You will probably need to wait until you have studied Chapter 7, "Classes: Part II," before you will be able to complete a reasonable working version of your simulator--so be patient and
implement only those portions of the elevator simulator that you can with the knowledge you have gained in Chapter 6. In Chapter 7 you will learn about composition, i.e., creating classes that contain other classes as members; this technique might help you represent the button, bell and door objects inside the elevator as members of the elevator, for example. Also in Chapter 7, you will learn how to create and destroy objects dynamically with new and delete; this will help you create new person objects as new people arrive in the simulation and destroy these person objects as people leave the simulation (after getting off the elevator).
3. For the first version of your simulator, design only a simple, text-oriented output that displays a message for each significant event that occurs. Your messages might include strings such as: "Person 1 arrives on Floor 1," "Person 1 presses Button on Floor 1," "Elevator arrives on Floor 1," "Person 1 enters Elevator," etc. Note that we suggest you capitalize the words of each message that represent objects in your simulation. Note also that you may choose to defer this portion of the lab assignment until you have read Chapter 7.
4. The more ambitious students will want to use an animated graphical output that shows the elevator moving up and down on the screen.
6.20 Summary
* Structures are aggregate data types built using data of other types. * The keyword struct introduces a structure definition. The body of a structure is delineated by braces ({ and }). Every structure definition must end with a semicolon. * A structure tag name can be used to declare variables of a structure type. * Structure definitions do not reserve space in memory; they create new data types that are used to declare variables. * Members of a structure or a class are accessed using
* the member access operators--the dot operator (.) and the arrow operator (->). The dot operator accesses a structure member via the object's variable name or a reference to the object. The arrow operator accesses a structure member via a pointer to the object. * Drawbacks to creating new data types with structs are the possibility of having uninitialized data; improper initialization; all programs using a struct must be changed if the struct implementation changes; and no protection is provided to ensure that data is kept in a consistent state with proper data values. * Classes enable the programmer to model objects with attributes and behaviors. Class types can be defined in * C++ using the keywords class and struct, but keyword class is normally used for this purpose. * The class name can be used to declare objects of that class. * Class definitions begin with the keyword class. The body of the class definition is delineated with braces ({ and }). Class definitions terminate with a semicolon. * Any data member or member function declared after public: in a class is visible to any function with access to an object of the class. * Any data member or member function declared after private: is only visible to friends and other members of the class. * Member access specifiers always end with a colon (:) and can appear multiple times and in any order in a class definition. * Private data are not accessible from outside the class. * The implementation of a class should be hidden from its clients. * A constructor is a special member function with the same name as the class that is used to initialize the members of a class object. A class's constructor is called when an object of that class is instantiated. * The function with the same name as the class but preceded with a tilde character (~) is called a destructor. * The set of public member functions of a class is * called the class's interface or public interface. * When a member function is defined outside the class definition, the function name is preceded by the class name and the binary scope resolution operator (::). * Member functions defined using the scope resolution operator outside a class definition are within that class's scope. * Member functions defined in a class definition are automatically inlined. The compiler reserves the right not to inline any function. * Calling member functions is more concise than calling functions in procedural programming because most data used by the member function is directly accessible * in the object. * Within a class's scope, class members may be referenced simply by their names. Outside a class's scope, class members are referenced through either an object name, a reference to an object, or a pointer to an object. * Member selection operators . and -> are used to access class members. * A fundamental principle of good software engineering is to separate interface from implementation. * Class definitions are normally placed in header files and member function definitions are normally placed in source-code files of the same base name. * The default access mode for classes is private so all * members after the class header and before the first member access specifier are considered to be private. * A class's public members present a view of the services the class provides to the clients of the class. * Access to a class's private data can be carefully controlled by the use of member functions called access functions. If a class wants to allow clients to read private data, the class can provide a get function. To enable clients to modify private data, the class can provide a set function. * Data members of a class are normally made private and member functions of a class are normally made public. Some member functions may be private and * serve as utility functions to the other functions of the class. * Data members of a class cannot be initialized in a class definition. They must be initialized in a constructor, or their values may be set after their object is created. * Constructors can be overloaded. * Once a class object is properly initialized, all member functions that manipulate the object should ensure that the object remains in a consistent state. * When an object of a class is declared, initializers can be provided. These initializers are passed to the class's constructor. * Constructors can specify default arguments. * Constructors may not specify return types, nor may they attempt to return values. * If no constructor is defined for a class, the compiler creates a default constructor. A default constructor supplied by the compiler does not perform any initialization, so when the object is created, it is not guaranteed to be in a consistent state. * The destructor of an automatic object is called when the object goes out of scope. The destructor itself does not actually destroy the object, but it does perform termination housekeeping before the system reclaims the object's storage. * Destructors do not receive parameters and do not return values. A class may have only one destructor (destructors cannot be overloaded). * The assignment operator (=) is used to assign an object to another object of the same type. Such assignment is normally performed by default memberwise copy. Memberwise copy is not ideal for all classes.
The fact that member function calls generally take either no arguments or substantially fewer arguments than conventional function calls in non-object- oriented languages reduces the likelihood
of passing the wrong arguments, the wrong types of arguments, and/or the wrong number of arguments.

Use #ifndef, #define and #endif preprocessor directives to prevent header files from being included more than once in a program.

Making the data members of a class private and the member functions of the class public facilitates debugging because problems with data manipulations are localized to either the class's member
functions or the friends of the class.

Every member function (and friend) that modifies the private data members of an object should ensure that the data remains in a consistent state.

The benefits of data integrity are not automatic simply because data members are made private--the programmer must provide the validity checking. C++ does, however, provide a framework in which
programmers can design better programs in a convenient manner.

A
abstract data type
access function
arrow member selection operator (->)
attribute
B
behavior
binary scope resolution operator (::)
C
class
class definition
class scope
client of a class
consistent state
constructors
D
data member
default constructor
destructor
dot member selection operator (.)
E
encapsulation
F
file scope
G
get function
global object
H
header file
helper function
I
implementation of a class
information hiding
initializing class objects
inline
interface of class
M
member access specifier
member function
member selection operators
memberwise copy
message sent to an object
O
object
object-oriented programming (OOP)
P
predicate function
principle of least privilege
private
procedural programming languages
programmer-defined type
protected
proxy class
public interface
Q
query function
R
rapid applications development (RAD)
reuse
S
scope resolution operator (::)
self-referential structure
service
set function
software reuse
source-code file
static local object
structure
T
tilde character (~)
U
user-defined type
utility function
Fig. 6.1 Creating a structure, setting its members, and printing the structure.
Fig. 6.2 Simple definition of class Time.
Fig. 6.3 Abstract data type Time implementation as a class.
Fig. 6.4 Accessing an object's data members and member functions through each type of object handle--through the object's name, through a reference, and through a pointer to the object.
Fig. 6.5 Separating Time class interface and implementation.
Fig. 6.6 Erroneous attempt to access private members of a class.
Fig. 6.7 Using a utility function.
Fig. 6.8 Using a constructor with default arguments.
Fig. 6.9 Demonstrating the order in which constructors and destructors are called.
Fig. 6.10 Using set and get functions.
Fig. 6.11 Returning a reference to a private data member.
Fig. 6.12 Assigning one object to another with default memberwise copy.

Exercise 6.1
Fill in the blanks in each of the following:
a) The keyword _______ introduces a structure definition.
b) Class members are accessed via the _______ operator in conjunction with the name of an object of the class or via the ________operator in conjunction with a pointer to an object of the class.
c) Members of a class specified as _______ are accessible only to member functions of the class and friends of the class.
d) A _______ is a special member function used to initialize the data members of a class.
e) The default access for members of a class is _______ .
f) A ________function is used to assign values to private data members of a class.
g) ________ can be used to assign an object of a class to another object of the same class.
h) Member functions of a class are normally made _______ and data members of a class are normally made ________.
i) A _______ function is used to retrieve values of private data of a class.
j) The set of public member functions of a class is referred to as the class's _____.
k) A class implementation is said to be hidden from its clients or ________.
l) The keywords _______ and _______ can be used to introduce a class definition.
m) Members of a class specified as _______ are accessible anywhere an object of the class is in scope.

Exercise 6.2
Find the error(s) in each of the following and explain how to correct it.
a) Assume the following prototype is declared in class Time.

void ~Time( int );

b) The following is a partial definition of class Time.

class Time {

public:

// function prototypes

private:

int hour = 0;

int minute = 0;


     int second = 0;


};

c) Assume the following prototype is declared in class Employee.

int Employee( const char *, const char * );


Exercise 6.3
What is the purpose of the scope resolution operator?

Exercise 6.4
Compare and contrast the notions of struct and class in C++.


Exercise 6.5
Provide a constructor that is capable of using the current time from the time() function--declared in the C Standard Library header time.h--to initialize an object of the Time class.
Exercise 6.6
Create a class called Complex for performing arithmetic with complex numbers. Write a driver program to test your class.
Complex numbers have the form

realPart + imaginaryPart * i

where i is
Use floating-point variables to represent the private data of the class. Provide a constructor function that enables an object of this class to be initialized when it is declared. The constructor should contain default values in case no initializers are provided. Provide public member functions for each of the following:
a) Addition of two Complex numbers: The real parts are added together and the imaginary parts are added together.
b) Subtraction of two Complex numbers: The real part of the right operand is subtracted from the real part of the left operand and the imaginary part of the right operand is subtracted from the imaginary part of the left operand.
c) Printing Complex numbers in the form (a, b) where a is the real part and b is the imaginary part.


Exercise 6.7
Create a class called Rational for performing arithmetic with fractions. Write a driver program to test your class.
Use integer variables to represent the private data of the class--the numerator and the denominator. Provide a constructor function that enables an object of this class to be initialized when it is declared. The constructor should contain default values in case no initializers are provided and should store the fraction in reduced form (i.e., the fraction
would be stored in the object as 1 in the numerator and 2 in the denominator). Provide public member functions for each of the following:
a) Addition of two Rational numbers. The result should be stored in reduced form.
b) Subtraction of two Rational numbers. The result should be stored in reduced form.
c) Multiplication of two Rational numbers. The result should be stored in reduced form.
d) Division of two Rational numbers. The result should be stored in reduced form.
e) Printing Rational numbers in the form a/b where a is the numerator and b is the denominator.
f) Printing Rational numbers in floating-point format.
Exercise 6.8
Modify the Time class of Fig. 6.10 to include a tick member function that increments the time stored in a Time object by one second. The Time object should always remain in a consistent state. Write a driver program that tests the tick member function in a loop that prints the time in standard format during each iteration of the loop to illustrate that the tick member function works correctly. Be sure to test the following cases:
a) Incrementing into the next minute.
b) Incrementing into the next hour.
c) Incrementing into the next day (i.e., 11:59:59 PM to 12:00:00 AM).
Exercise 6.9
Modify the Date class of Fig. 6.12 to perform error checking on the initializer values for data members month, day, and year. Also, provide a member function nextDay to increment the day by one. The Date object should always remain in a consistent state. Write a driver program that tests the nextDay function in a loop that prints the date during each iteration of the loop to illustrate that the nextDay function works correctly. Be sure to test the following cases:
a) Incrementing into the next month.
b) Incrementing into the next year.


Exercise 6.10
Combine the modified Time class of Exercise 6.8 and the modified Date class of Exercise 6.9 into one class called DateAndTime (in Chapter 9 we will discuss inheritance which will enable us to accomplish this task quickly without modifying the existing class definitions). Modify the tick function to call the nextDay function if the time is incremented into the next day. Modify function printStandard and printMilitary to output the date in addition to the time. Write a driver program to test the new class DateAndTime. Specifically test incrementing the time into the next day.


Exercise 6.11
Modify the set functions in the program of Fig. 6.10 to return appropriate error values if an attempt is made to set a data member of an object of class Time to an invalid value.


Exercise 6.12
Create a class Rectangle. The class has attributes length and width, each of which defaults to 1. It has member functions that calculate the perimeter and the area of the rectangle. It has set and get functions for both length and width. The set functions should verify that length and width are each floating-point numbers larger than 0.0 and less than 20.0.
Exercise 6.13
Create a more sophisticated Rectangle class than the one you created in Exercise 6.12. This class stores only the Cartesian coordinates of the four corners of the rectangle. The constructor calls a set function that accepts four sets of coordinates and verifies that each of these is in the first quadrant with no single x or y coordinate larger than 20.0. The set function also verifies that the supplied coordinates do, in fact, specify a rectangle. Member functions calculate the length, width, perimeter, and area. The length is the larger of the two dimensions. Include a predicate function square that determines if the rectangle is a square.


Exercise 6.14
Modify the Rectangle class of Exercise 6.13 to include a draw function that displays the rectangle inside a 25-by-25 box enclosing the portion of the first quadrant in which the rectangle resides. Include a setFillCharacter function to specify the character out of which the body of the rectangle will be drawn. Include a setPerimeterCharacter function to specify the character that will be used to draw the border of the rectangle. If you feel ambitious you might include functions to scale the size of the rectangle, rotate it, and move it around within the designated portion of the first quadrant.


Exercise 6.15
Create a class HugeInteger that uses a 40-element array of digits to store integers as large as 40-digits each. Provide member functions inputHugeInteger, outputHugeInteger, addHugeIntegers, and substractHugeIntegers. For comparing HugeInteger objects provide functions isEqualTo, isNotEqualTo, isGreaterThan, isLessThan, IsGreaterThanOrEqualTo, and isLessThanOrEqualTo--each of these is a "predicate" function that simply returns true if the relationship holds between the two huge integers and returns false if the relationship does not hold. Provide a predicate function isZero. If you feel ambitious, also provide member functions multiplyHugeIntegers, divideHugeIntegers, and modulusHugeIntegers.
Exercise 6.16
Create a class TicTacToe that will enable you to write a complete program to play the game of tic-tac-toe. The class contains as private data a 3-by-3 double array of integers. The constructor should initialize the empty board to all zeros. Allow two human players. Wherever the first player moves, place a 1 in the specified square; place a 2 wherever the second player moves. Each move must be to an empty square. After each move, determine if the game has been won or if the game is a draw. If you feel ambitious, modify your program so that the computer makes the moves for one of the players automatically. Also, allow the player to specify whether he or she wants to go first or second. If you feel exceptionally ambitious, develop a program that will play three-dimensional tic- tac-toe on a 4-by-4-by-4 board (Caution: This is an extremely challenging project that could take many weeks of effort!).
* To understand the software engineering concepts of encapsulation and data hiding. * To understand the notions of data abstraction and abstract data types (ADTs). * To be able to create C++ ADTs, namely classes. * To understand how to create, use, and destroy class objects. * To be able to control access to object data members and member functions. * To begin to appreciate the value of object orientation.
Figure 6.1 Creating a structure, setting its members, and printing the structure.



Figure 6.2 Simple definition of class Time.



Figure 6.3 Abstract data type Time implementation as a class.



Figure 6.4 Accessing an object's data members and member functions through each type of object handle--through the object's name, through a reference, and through a pointer to the object.



Figure 6.5 Separating Time class interface and implementation.



Figure 6.6 Erroneous attempt to access private members of a class.



Figure 6.7 Using a utility function.



Figure 6.8 Using a constructor with default arguments.



Figure 6.9 Demonstrating the order in which constructors and destructors are called.



Figure 6.10 Using set and get functions.



Figure 6.11 Returning a reference to a private data member.



Figure 6.12 Assigning one object to another with default memberwise copy.



Structures are ordinarily passed call- by-value. To avoid the overhead of copying a structure, pass the structure call-by- reference.

Defining a small member function inside the class definition automatically inlines the member function (if the compiler chooses to do so). This can improve performance, but it does not promote the best software
engineering because clients of the class will be able to see the implementation of the function.

Actually objects contain only data, so objects are much smaller than if they also contained functions. Applying operator sizeof to a class name or to an object of that class will report only the size of the class's
data. The compiler creates one copy (only) of the class's member functions separate from all objects of the class. All objects of the class share this one copy of the member functions. Each object, of course, needs its own copy of
the class's data because this data can vary among the objects. The function code is nonmodifiable (also called reentrant code or pure procedure) and hence can be shared among all objects of one class.
Passing an object call- by-value is good from a security standpoint because the called function has no access to the original object, but call-by-value can degrade performance when making a copy of a large object. An
object can be passed call-by-reference by passing either a pointer or a reference to the object. Call-by- reference offers good performance but is weaker from a security standpoint because the called function is given
access to the original object. Call-by-const- reference is a safe, good-performing alternative.

Use each member access specifier only once in a class definition for clarity and readability. Place public members first where they are easy to locate.

Use the name of the header file with the period replaced by an underscore in the #ifndef and #define preprocessor directives of a header file.

Despite the fact that the public and private labels may be repeated and intermixed, list all the public members of a class first in one group and then list all the private members in another group. This focuses the client's
attention on the class's public interface, rather than on the class's implementation.

If you choose to list the private members first in a class definition, explicitly use the private label despite the fact that private is assumed by default. This improves program clarity. Our preference is to list the public
members of a class first to emphasize the class's interface.

When appropriate (almost always), provide a constructor to ensure that every object is properly initialized with meaningful values. Pointer data members, in particular, should be initialized to
some legitimate pointer value or to 0.

Declare default function argument values only in the function prototype within the class definition in the header file.

Member functions that set the values of private data should verify that the intended new values are proper; if they are not, the set functions should place the private data members into an appropriate consistent state.
Never have a public member function return a non-const reference (or a pointer) to a private data member. Returning such a reference violates the encapsulation of the class.

The expression (*timePtr).hour refers to the hour member of the struct pointed to by timePtr. Omitting the parentheses as in *timePtr.hour would be a syntax error because . has a higher precedence than * so
the expression would execute as if parenthesized as *(timePtr.hour). This would be a syntax error because with a pointer you must use the arrow operator to refer to a member

Forgetting the semicolon at the end of a class (or structure) definition is a syntax error.

Specifying a return type and/or a return value for a constructor is a syntax error.

Attempting to initialize a data member of a class explicitly in the class definition is a syntax error.

When defining a class's member functions outside that class, omitting the class name and scope resolution operator on the function name is a syntax error.

An attempt by a function which is not a member of a particular class (or a friend of that class) to access a private member of that class is a syntax error.

Data members of a class cannot be initialized in the class definition.

Attempting to declare a return type for a constructor and/or attempting to return a value from a constructor are syntax errors.

Specifying default initializers for the same member function in both a header file and in the member function definition.

It is a syntax error to attempt to pass arguments to a destructor, to specify a return type for a destructor (even void cannot be specified), to return values from a destructor, or to overload a destructor.
A constructor can call other member functions of the class such as set or get functions, but because the constructor is initializing the object, the data members may not yet be in a consistent state. Using data members
before they have been properly initialized can cause logic errors.

To avoid the overhead of call-by-value yet still gain the benefit that the caller's original data is protected from modification, pass large-size arguments as const references.

It is important to write programs that are understandable and easy to maintain. Change is the rule rather than the exception. Programmers should anticipate that their code will be modified.
As we will see, classes can facilitate program modifiability.

Clients of a class use the class without knowing the internal details of how the class is implemented. If the class implementation is changed (to improve performance, for example), provided the class's interface
remains constant, the class's client source code need not change (although the client may need to be recompiled). This makes it much easier to modify systems.

Member functions are usually shorter than functions in non-object- oriented programs because the data stored in data members has ideally been validated by a constructor and/or by member functions that store new data.
Because the data is already the object, the member function calls often have no arguments or at least have fewer arguments than typical function calls in non-object- oriented languages. Thus, the calls are
shorter, the function definitions are shorter and the function prototypes are shorter.

Clients have access to a class's interface but should not have access to a class's implementation.

Declaring member functions inside a class definition (via their function prototypes) and defining those member functions outside that class definition separates the interface of a class from its implementation.
This promotes good software engineering. Clients of a class cannot see the implementation of that class's member functions.

Only the simplest member functions should be defined in the class header.

Using an object- oriented programming approach can often simplify function calls by reducing the number of parameters to be passed. This benefit of object-oriented programming derives from the fact that
encapsulation of data members and member functions within an object gives the member functions the right to access the data members.

A central theme of this book is "reuse, reuse, reuse." We will carefully discuss a number of techniques for "polishing" classes to encourage reuse. We focus on "crafting valuable classes" and
creating valuable "software assets."

Clients of a class do not need access to the class's source code in order to use the class. The clients do, however, need to be able to link to the class's object code. This encourages independent software
vendors (ISVs) to provide class libraries for sale or license. The ISVs provide in their products only the header files and the object modules. No proprietary information is revealed--as would be the case if source
code were provided. The C++ user community benefits by having more ISV- produced class libraries available.

Place the class declaration in a header file to be included by any client that wants to use the class. This forms the class's public interface (and provides the client with the function prototypes it needs to be able to call
the class's member functions). Place the definitions of the class member functions in a source file. This forms the implementation of the class.

Information important to the interface to a class should be included in the header file. Information that will be used only internally in the class and will not be needed by clients of the class should be included in
the unpublished source file. This is yet another example of the principle of least privilege.

C++ encourages programs to be implementation independent. When the implementation of a class used by implementation- independent code changes, that code need not be modified, but it
may need to be recompiled.

Keep all the data members of a class private. Provide public member functions to set the values of private data members and to get the values of private data members. This architecture helps hide the
implementation of a class from its clients, which reduces bugs and improves program modifiability.

Class designers use private, protected, and public members to enforce the notion of information hiding and the principle of least privilege.

The class designer need not provide set and/or get functions for each private data item; these capabilities should be provided only when appropriate.

Member functions tend to fall into a number of different categories: functions that read and return the value of private data members; functions that set the value of private data members; functions that implement the
features of the class; and functions that perform various mechanical chores for the class such as initializing class objects, assigning class objects, converting between classes and built-in types or
between classes and other classes, and handling memory for class objects.

A phenomenon of object-oriented programming is that once a class is defined, creating and manipulating objects of that class usually involves issuing only a simple sequence of member function
calls--few, if any, control structures are needed. By contrast, it is common to have control structures in the implementation of a class's member functions.

If a member function of a class already provides all or part of the functionality required by a constructor (or other member function) of the class, call that member function from the constructor (or other member
function). This simplifies the maintenance of the code and reduces the likelihood of an error if the implementation of the code is modified. As a general rule: Avoid repeating code.

It is possible for a class not to have a default constructor.

As we will see (throughout the remainder of the book), constructors and destructors have much greater prominence in C++ and object- oriented programming than is possible to
convey after only our brief introduction here.

Making data members private and controlling access, especially write access, to those data members through public member functions helps ensure data integrity.

Accessing private data through set and get member functions not only protects the data members from receiving invalid values, but it also insulates clients of the class from the representation of the
data members. Thus, if the representation of the data changes for some reason (typically to reduce the amount of storage required or to improve performance), only the member functions need to change--the clients
need not change as long as the interface provided by the member functions remains the same. The clients may, however, need to be recompiled.

This chapter does not contain any Portability tips.
This chapter does not contain any Applet Examples.